package info.hengha.blue.dao;

import info.hengha.blue.model.Node;
import info.hengha.blue.model.NodeTaxonomy;
import info.hengha.blue.model.Term;
import info.hengha.blue.model.TermTaxonomy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;

public class NodeDao {

    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Node getNode(int id) {
        Node node = null;
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        Session s = sessionFactory.openSession();
        s.getTransaction().begin();
        node = s.get(Node.class, id);
        if (node != null) {
            Query q = s.createQuery("select metaVarchar from NodeMeta where nodeId=:id");
            q.setInteger("id", id);
            List<String> images = q.list();
            node.setImages(images);
        }
        s.getTransaction().commit();
        return node;
    }

    private List<Integer> getRandomIdArray(int n, int max) {
        n = n > max ? max : n;
        Set<Integer> s = new HashSet<Integer>();
        Random rand = new Random();
        while (s.size() < n) {
            s.add(rand.nextInt(max));
        }
        List<Integer> list = new ArrayList<Integer>(s);
        return list;
    }

    public List<Node> getRandomNodes(int size) {
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        Session s = sessionFactory.openSession();
        s.getTransaction().begin();
        Integer m = (Integer) s.createQuery("select max(a.id) from info.hengha.blue.model.Node a ").uniqueResult();
        Set<Node> nodes = new HashSet<Node>();
        /*
         Query q = s.createQuery("select id,title,createdAt from info.hengha.blue.model.Node where id in (:idlist)");
         for (int i = 0; i < 3; i++) {
         List<Integer> ids = getRandomIdArray(60, m);
         q.setParameterList("idlist", ids);
         nodes.addAll((List<Node>) q.list());
         }
         */
        Criteria c = s.createCriteria(Node.class)
                .add(Restrictions.eq("nodeType", "blue"))
                .setProjection(Projections.projectionList()
                        .add(Projections.property("id"), "id")
                        .add(Projections.property("title"), "title")
                        .add(Projections.property("createdAt"), "createdAt"))
                .setResultTransformer(Transformers.aliasToBean(info.hengha.blue.model.Node.class));
        for (int i = 0; i < 3; i++) {
            // if (nodes.size() >= size) {
            // break;
            // }
            List<Integer> ids = getRandomIdArray(40, m);
            c.add(Restrictions.in("id", ids));
            nodes.addAll(c.list());
        }

        List<Node> n = new ArrayList<Node>(nodes);
        s.getTransaction().commit();
        s.close();
        size = size > n.size() ? n.size() : size;
        return n.subList(0, size);
    }

    public List<Node> getRandomNodes2(int size) {
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        Session s = sessionFactory.openSession();
        s.getTransaction().begin();
        Integer m = (Integer) s.createQuery("select count(a.id) from info.hengha.blue.model.Node a ").uniqueResult();
        Set<Node> nodes = new HashSet<Node>();
        /*
         Query q = s.createQuery("select id,title,createdAt from info.hengha.blue.model.Node where id in (:idlist)");
         for (int i = 0; i < 3; i++) {
         List<Integer> ids = getRandomIdArray(60, m);
         q.setParameterList("idlist", ids);
         nodes.addAll((List<Node>) q.list());
         }
         */
        Criteria c = s.createCriteria(Node.class)
                .add(Restrictions.eq("nodeType", "blue"))
                .setProjection(Projections.projectionList()
                        .add(Projections.property("id"), "id")
                        .add(Projections.property("title"), "title")
                        .add(Projections.property("createdAt"), "createdAt"))
                .setResultTransformer(Transformers.aliasToBean(info.hengha.blue.model.Node.class))
                .setMaxResults(1);

        for (int i = 0; i < 3; i++) {
            if (nodes.size() >= size) {
                break;
            }
            List<Integer> ids = getRandomIdArray(40, m);
            for (Integer id : ids) {
                c.setFirstResult(id);
                nodes.add((Node) c.uniqueResult());
            }
            c.add(Restrictions.in("id", ids));
            nodes.addAll(c.list());
        }

        List<Node> n = new ArrayList<Node>(nodes);
        s.getTransaction().commit();
        s.close();
        size = size > n.size() ? n.size() : size;
        return n.subList(0, size);
    }

    public List<Node> getRandomNodesByCategory(String cat, int size) {
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        Session s = sessionFactory.openSession();
        s.getTransaction().begin();
        List<Integer> categoryIds = getChildrenCategoryIdCollection(s, cat);

        Integer m = (Integer) s.createQuery("select max(a.nodeId) from info.hengha.blue.model.NodeTaxonomy a where termTaxonomyId in ?0").setParameterList("0", categoryIds).uniqueResult();
        Set<Node> nodes = new HashSet<Node>();
        /*
         Query q = s.createQuery("select id,title,createdAt from info.hengha.blue.model.Node where id in (:idlist)");
         for (int i = 0; i < 3; i++) {
         List<Integer> ids = getRandomIdArray(60, m);
         q.setParameterList("idlist", ids);
         nodes.addAll((List<Node>) q.list());
         }
         */
        // 使用关联查询过虑类型
        Criteria c = s.createCriteria(Node.class)
                .add(Restrictions.eq("nodeType", "blue"))
                .setProjection(Projections.projectionList()
                        .add(Projections.property("id"), "id")
                        .add(Projections.property("title"), "title")
                        .add(Projections.property("createdAt"), "createdAt"))
                .setResultTransformer(Transformers.aliasToBean(info.hengha.blue.model.Node.class));
        for (int i = 0; i < 3; i++) {
            // if (nodes.size() >= size) {
            // break;
            // }
            List<Integer> ids = getRandomIdArray(40, m);
            c.add(Restrictions.in("id", ids));
            nodes.addAll(c.list());
        }

        List<Node> n = new ArrayList<Node>(nodes);
        s.getTransaction().commit();
        s.close();
        size = size > n.size() ? n.size() : size;
        return n.subList(0, size);
    }

    public List<Node> getNodes(int page, int size) {
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        List<Node> list;
        try (Session s = sessionFactory.openSession()) {
            s.getTransaction().begin();
            /*
             Query q = s.createQuery("select id,title,createdAt from info.hengha.blue.model.Node a where a.nodeType = 'blue' order by a.id desc")
             .setFirstResult((page - 1) * size)
             .setMaxResults(size);
             list = (List<Node>) q.list();
             */
            Criteria c = s.createCriteria(Node.class)
                    .setProjection(Projections.projectionList()
                            .add(Projections.property("id"), "id")
                            .add(Projections.property("title"), "title")
                            .add(Projections.property("createdAt"), "createdAt"))
                    .setResultTransformer(Transformers.aliasToBean(info.hengha.blue.model.Node.class))
                    .add(Restrictions.eq("nodeType", "blue"))
                    .addOrder(Order.desc("id"))
                    .setFirstResult((page - 1) * size)
                    .setMaxResults(size);
            list = c.list();
            s.getTransaction().commit();
        }
        return list;
    }

    private List<Integer> getChildrenCategoryIdCollection(Session s, String slug) {
        List<Integer> categoryIds = new ArrayList<Integer>();
        s.getTransaction().begin();
        Query q = null;
        if (slug != null) {
            q = s.createQuery("from Term where slug = :slug");
            q.setParameter("slug", slug);
            Term term = (Term) q.uniqueResult();
            if (term != null) {
                q = s.createQuery("from TermTaxonomy where termId=:id");
                q.setParameter("id", term.getId());
                TermTaxonomy tt = (TermTaxonomy) q.uniqueResult();
                if (tt != null) {
                    categoryIds.add(tt.getId());
                    q = s.createQuery("select id from TermTaxonomy where parentId=:id");
                    q.setParameter("id", tt.getId());

                    categoryIds.addAll(q.list());
                }
            }
        }
        s.getTransaction().commit();
        return categoryIds;
    }

    private List<Integer> getChildrenCategoryIdCollection(String slug) {
        List<Integer> categoryIds = new ArrayList<Integer>();
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        try (Session s = sessionFactory.openSession()) {
            s.getTransaction().begin();
            Query q = null;
            if (slug != null) {
                q = s.createQuery("from Term where slug = :slug");
                q.setParameter("slug", slug);
                Term term = (Term) q.uniqueResult();
                if (term != null) {
                    q = s.createQuery("from TermTaxonomy where termId=:id")
                            .setParameter("id", term.getId());
                    TermTaxonomy tt = (TermTaxonomy) q.uniqueResult();
                    if (tt != null) {
                        categoryIds.add(tt.getId());
                        q = s.createQuery("select id from TermTaxonomy where parentId=:id");
                        q.setParameter("id", tt.getId());

                        categoryIds.addAll(q.list());
                    }
                }
            }
            s.getTransaction().commit();
        }
        return categoryIds;
    }

    public List<Node> getNodesByCategorySlug(String slug, int page, int size) {
        //SessionFactory sf = pw.yitree.work.mmsh.HibernateUtil.getFactory();
        List<Node> nodes;
        try (Session s = sessionFactory.openSession()) {
            s.getTransaction().begin();
            List<Integer> categoryIds = getChildrenCategoryIdCollection(s, slug);
            Criteria c = s.createCriteria(NodeTaxonomy.class)
                    .setProjection(Property.forName("nodeId"));
            if (categoryIds.size() > 0) {
                c.add(Restrictions.in("termTaxonomyId", categoryIds));
            }

            List<Integer> nodeIds = c.addOrder(Order.desc("nodeId")).
                    setFirstResult((page - 1) * size).
                    setMaxResults(size).list();
            c = s.createCriteria(Node.class)
                    .setProjection(Projections.projectionList()
                            .add(Projections.property("id"), "id")
                            .add(Projections.property("title"), "title")
                            .add(Projections.property("createdAt"), "createdAt"))
                    .setResultTransformer(Transformers.aliasToBean(info.hengha.blue.model.Node.class));
            if (nodeIds.size() > 0) {
                c.add(Restrictions.in("id", nodeIds));
            }
            c.addOrder(Order.desc("id"));
            nodes = (List<Node>) c.list();
            s.getTransaction().commit();
        }
        return nodes;
    }
}
